package cn.bluethink.eguan.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES对称加密算法工具类
 * 
 * @author 苏州中科蓝迪公司所有(c)2016-2021
 * @version 0.3.0
 * @brief 驿馆+产品
 * @note 修订历史： 1.wanglei于2019/01/08设计并构建初始版本v0.3.0
 */
public class AESUtils {

    /**
     * 加密规则
     */
    private static final String ENCODE_RULES = "http://www.bluethink.cn";

    /**
     * 字符串分割符
     */
    private static final String SPLIT_CHAR = "&";

    /**
     * 有效期24小时
     */
    private static final long EXP_Millis = 1000 * 60 * 60 * 24;

    private static final String HEX_NUMS_STR = "0123456789ABCDEF";

    /**
     * 加密
     * 
     * @param ecodeContent
     * @return
     */
    public static String encodeASE(String ecodeContent) {
        try {
            // 1.构造密钥生成器，指定为AES算法,不区分大小写
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(ENCODE_RULES.getBytes());
            keygen.init(128, secureRandom);
            // 3.产生原始对称密钥
            SecretKey originalKey = keygen.generateKey();
            // 4.获得原始对称密钥的字节数组
            byte[] raw = originalKey.getEncoded();
            // 5.根据字节数组生成AES密钥
            SecretKey key = new SecretKeySpec(raw, "AES");
            // 6.根据指定算法AES自成密码器
            Cipher cipher = Cipher.getInstance("AES");
            // 7.初始化密码器，第一个参数为加密或者解密操作，第二个参数为使用的KEY
            cipher.init(Cipher.ENCRYPT_MODE, key);
            // 8.被加密内容&+当前时间戳+有效期 组合
            ecodeContent = String.valueOf(System.currentTimeMillis() + EXP_Millis) + SPLIT_CHAR + ecodeContent;
            // 9.获取加密内容的字节数组
            byte[] byteEncode = ecodeContent.getBytes("UTF-8");
            // 10.根据密码器的初始化方式--加密：将数据加密
            byte[] byteAES = cipher.doFinal(byteEncode);
            // 11.将加密后的数据转换为字符
            // String encodeString = new
            // String(Base64.encodeBase64(byteAES),Charset.forName("UTF-8"));
            String encodeString = byteToHexString(byteAES);
            // 12.将字符串返回
            return encodeString;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     * 
     * @param deCodeContent
     * @return
     */
    public static String decodeASE(String deCodeContent) throws IOException {
        try {
            // 1.构造密钥生成器，指定为AES算法,不区分大小写
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(ENCODE_RULES.getBytes());
            keygen.init(128, secureRandom);
            // 3.产生原始对称密钥
            SecretKey originalKey = keygen.generateKey();
            // 4.获得原始对称密钥的字节数组
            byte[] raw = originalKey.getEncoded();
            // 5.根据字节数组生成AES密钥
            SecretKey key = new SecretKeySpec(raw, "AES");
            // 6.根据指定算法AES自成密码器
            Cipher cipher = Cipher.getInstance("AES");
            // 7.初始化密码器，第一个参数为加密或者解密操作，第二个参数为使用的KEY
            cipher.init(Cipher.DECRYPT_MODE, key);
            // 8.将加密并编码后的内容解码成字节数组
            // byte[] byteContent = Base64.decodeBase64(deCodeContent);
            byte[] byteContent = hexStringToByte(deCodeContent);
            // 9.解密
            byte[] byteDecode = cipher.doFinal(byteContent);
            // 10.将解密后的数据转为字符串
            String aesDecode = new String(byteDecode, Charset.forName("UTF8"));
            // 11.获取该字符串的时间戳
            String ecodeMillis = aesDecode.split(SPLIT_CHAR)[0].toString();
            // 12.获取该字符串的被加密内容
            String ecodeContent = aesDecode.split(SPLIT_CHAR)[1].toString();
            // 13.如果超过有效期，就返回null
            if (System.currentTimeMillis() > Long.parseLong(ecodeMillis)) {
                return "LinkRot";
            }
            // 14.返回字符串
            return ecodeContent;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将指定byte数组转换成16进制字符串
     * 
     * @param b
     * @return
     */
    private static String byteToHexString(byte[] b) {
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            hexString.append(hex.toUpperCase());
        }
        return hexString.toString();
    }

    /**
     * 将16进制字符串转换成字节数组
     * 
     * @param hex
     * @return
     */
    private static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] hexChars = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (HEX_NUMS_STR.indexOf(hexChars[pos]) << 4 | HEX_NUMS_STR.indexOf(hexChars[pos + 1]));
        }
        return result;
    }
}
